﻿/*************************************
 * Creator:SW-PeiYang
 * DateTime:2023/12/8 9:57:53
 * Description:<Description>
 * CopyRight:中广核研究院有限公司
 * ***********************************/

using Cpjit.SunnyPaine.Toolkit.Net.Sockets.Model;
using System;
using System.Collections.Generic;
using System.Net.Sockets;

namespace Cpjit.SunnyPaine.Toolkit.Net.Sockets.IDataHandlingApdapter.TCP
{
    /// <summary>
    /// 提供一个固定包头协议的数据包处理器。
    /// <para>
    /// 一条数据包由“包头+用户数据+终止符（\0）”组成。<br></br>
    /// 作用原理：<br></br>
    /// 1.粘包的拆分。根据包头指示的数据长度决定游标读取完整数据的位置，并由终止符判定数据完整性和合法性。<br></br>
    /// 2.分包的缝合。用户数据的分包缝合，直接根据游标判断是否需要从下一条接收到的数据中获取；包头的分包缝合，根据包头的完整性判断下一条数据的起始的n个字节为上一条末尾的包头进行缝合。
    /// </para>
    /// </summary>
    public class FixHeaderDataHandlingAdapter : AbstractDataHandlingApdapter
    {
        #region 私有变量
        private byte[] header;
        private int remaidHeaderCount = 0;
        #endregion


        #region 构造方法
        /// <summary>
        /// 使用默认的参数创建<see cref="FixHeaderDataHandlingAdapter"/>的实例。
        /// </summary>
        public FixHeaderDataHandlingAdapter()
        {
            this.lastCacheTime = DateTime.Now;
            this.isRunning = true;
        }
        #endregion


        #region 公共方法，AbstractDataHandlingApdapter成员
        /// <summary>
        /// 消息接收前处理。
        /// </summary>
        /// <param name="session"></param>
        public override void PreviewReceived(SocketSession session)
        {
            if (this.isRunning == false)
            {
                return;
            }

            if (this.UseCacheTime && DateTime.Now - this.lastCacheTime > this.cacheTimeout)
            {
                this.tempData?.Reset();
            }
            this.lastCacheTime = DateTime.Now;

            int index = 0;
            while (index < session.ReceivedCount)
            {
                if (this.header != null)//缝合包头
                {
                    int startIndex = 4 - this.remaidHeaderCount;
                    for (int i = startIndex; i < 4; i++)
                    {
                        this.header[i] = session.Buffer[index++];
                    }
                    int dataLength = BitConverter.ToInt32(this.header, 0);
                    this.tempData = new ByteBlock(dataLength);
                    this.header = null;
                    this.remaidHeaderCount = 0;
                }
                else if (this.tempData == null)//新的数据
                {
                    int remaindByteCount = session.ReceivedCount - index;
                    if (remaindByteCount < 4)
                    {
                        this.header = new byte[4];
                        for (int i = 0; i < remaindByteCount; i++)
                        {
                            this.header[i] = session.Buffer[index++];
                        }
                        this.remaidHeaderCount = 4 - remaindByteCount;
                    }
                    else
                    {
                        int dataLength = BitConverter.ToInt32(session.Buffer, index);
                        this.tempData = new ByteBlock(dataLength);
                        index += 4;
                        continue;
                    }
                }

                if (this.tempData == null)
                {
                    continue;
                }
                //是否中止
                if (this.tempData.WriteIndex == this.tempData.Capacity)
                {
                    if (session.Buffer[index] == '\0')
                    {
                        this.GoReceivedHandle(session, this.tempData.ToAarray());
                        this.tempData = null;
                    }
                    else//无效数据
                    {
                        this.tempData = null;
                    }
                    index++;
                }
                else
                {
                    this.tempData.WriteValue(session.Buffer[index]);
                    index++;
                }
            }
        }

        /// <summary>
        /// 消息发送前处理。
        /// </summary>
        /// <param name="remote">远端Socket实例。</param>
        /// <param name="datas">要发送的数据。</param>
        /// <param name="isAsync">是否异步发送。true：异步，false：同步。</param>
        public override void PreviewSend(Socket remote, byte[] datas, bool isAsync)
        {
            byte[] packageDatas = this.PreviewSendHandle(datas);
            base.PreviewSend(remote, packageDatas, isAsync);
        }

        /// <summary>
        /// 消息发送前处理。
        /// </summary>
        /// <param name="remotes">远端Socket实例。</param>
        /// <param name="datas">要发送的数据。</param>
        /// <param name="isAsync">是否异步发送。true：异步，false：同步。</param>
        public override void PreviewSend(List<Socket> remotes, byte[] datas, bool isAsync)
        {
            byte[] packageDatas = this.PreviewSendHandle(datas);
            base.PreviewSend(remotes, packageDatas, isAsync);
        }
        #endregion


        #region 私有方法
        private byte[] PreviewSendHandle(byte[] datas)
        {
            ByteBlock block = new ByteBlock(4 + datas.Length + 1);
            //写入数据长度
            block.WriteValue(datas.Length);
            //写入数据
            block.WriteValue(datas);
            //写入休止符
            block.EndWrite();
            return block.ToAarray();
        }
        #endregion
    }
}
